package alexAI;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
/**
 * References: 
 * http://chessprogramming.wikispaces.com/BitScan
 * http://chessprogramming.wikispaces.com/General+Setwise+Operations
 * http://en.wikipedia.org/wiki/Bitboard
 * @author Alex
 *
 */
public class BitBoard {
	public static int masterCpt = 0;
	//private static int[] score = new int[2];
	private static int score; 
	private static int[] tmpInt = new int[2];

	private static boolean playerWhite = true;
	private static final Map<String, Integer> POS_TO_INDEX =  createPositionToIndexMap();
	private static final Map<Integer, String> INDEX_TO_POS =  createIndexToPositionMap();
	private static Map<Integer, Long> CAPTURED_PIECES = new HashMap<Integer, Long>();
	private static Map<Integer, Integer> CAPTURED_PIECES_INDEX = new HashMap<Integer, Integer>();
	private static int moveNumber = 0;

	private static Map<String, Integer> createPositionToIndexMap() {
		Map<String, Integer> result = new HashMap<String, Integer>();
		for(int i = 0; i <= 63; i++) {
			result.put((char)(65+(i%8))+""+(i+8)/8, i);
		}
		return Collections.unmodifiableMap(result);
	}

	private static Map<Integer, String> createIndexToPositionMap() {
		Map<Integer, String> result = new HashMap<Integer, String>();
		for(int i = 0; i <= 63; i++) {
			result.put(i, (char)(65+(i%8))+""+(i+8)/8);
		}	
		return Collections.unmodifiableMap(result);
	}

	static long BLACK_PUSHEE_1 = 281474976710656L;
	static long BLACK_PUSHEE_2 = 562949953421312L;
	static long BLACK_PUSHEE_3 = 1125899906842624L;
	static long BLACK_PUSHEE_4 = 2251799813685248L;
	static long BLACK_PUSHEE_5 = 4503599627370496L;
	static long BLACK_PUSHEE_6 = 9007199254740992L;
	static long BLACK_PUSHEE_7 = 18014398509481984L;
	static long BLACK_PUSHEE_8 = 36028797018963968L;

	static long BLACK_PUSHER_1 = 72057594037927936L;
	static long BLACK_PUSHER_2 = 144115188075855872L;
	static long BLACK_PUSHER_3 = 288230376151711744L;
	static long BLACK_PUSHER_4 = 576460752303423488L;
	static long BLACK_PUSHER_5 = 1152921504606846976L;
	static long BLACK_PUSHER_6 = 2305843009213693952L;
	static long BLACK_PUSHER_7 = 4611686018427387904L;
	static long BLACK_PUSHER_8 = -9223372036854775808L;

	static final long[] ALL_BLACK_LIST = {
		BLACK_PUSHEE_1 , BLACK_PUSHEE_2 , BLACK_PUSHEE_3 , BLACK_PUSHEE_4 , BLACK_PUSHEE_5 , BLACK_PUSHEE_6 , BLACK_PUSHEE_7 , BLACK_PUSHEE_8,
		BLACK_PUSHER_1 , BLACK_PUSHER_2 , BLACK_PUSHER_3 , BLACK_PUSHER_4 , BLACK_PUSHER_5 , BLACK_PUSHER_6 , BLACK_PUSHER_7 , BLACK_PUSHER_8	
	};

	static long WHITE_PUSHER_1 = 1L;
	static long WHITE_PUSHER_2 = 2L;
	static long WHITE_PUSHER_3 = 4L;
	static long WHITE_PUSHER_4 = 8L;
	static long WHITE_PUSHER_5 = 16L;
	static long WHITE_PUSHER_6 = 32L;
	static long WHITE_PUSHER_7 = 64L;
	static long WHITE_PUSHER_8 = 128L;

	static long WHITE_PUSHEE_1 = 256L;
	static long WHITE_PUSHEE_2 = 512L;
	static long WHITE_PUSHEE_3 = 1024L;
	static long WHITE_PUSHEE_4 = 2048L;
	static long WHITE_PUSHEE_5 = 4096L;
	static long WHITE_PUSHEE_6 = 8192L;
	static long WHITE_PUSHEE_7 = 16384L;
	static long WHITE_PUSHEE_8 = 32768L;	

	static long[] ALL_WHITE_LIST = {
		WHITE_PUSHEE_1 , WHITE_PUSHEE_2 , WHITE_PUSHEE_3 , WHITE_PUSHEE_4 , WHITE_PUSHEE_5 , WHITE_PUSHEE_6 , WHITE_PUSHEE_7 , WHITE_PUSHEE_8,
		WHITE_PUSHER_1 , WHITE_PUSHER_2 , WHITE_PUSHER_3 , WHITE_PUSHER_4 , WHITE_PUSHER_5 , WHITE_PUSHER_6 , WHITE_PUSHER_7 , WHITE_PUSHER_8	
	};

	static long WPE = 65280L;
	static long WPR = 255L;
	static long BPE = 71776119061217280L;
	static long BPR = -72057594037927936L;
	static long ALL_PIECES = WPE | WPR | BPE | BPR;
	static long ALL_WHITE = WPE | WPR;
	static long ALL_BLACK = BPE | BPR;

	static final long RANK1 = 255L;
	static final long RANK2 = 65280L;
	static final long RANK3 = 16711680L;
	static final long RANK4 = 4278190080L;
	static final long RANK5 = 1095216660480L;
	static final long RANK6 = 280375465082880L;
	static final long RANK7 = 71776119061217280L;
	static final long RANK8 = -72057594037927936L;

	static final long AFile = 72340172838076673L;
	static final long BFile = 144680345676153346L;
	static final long CFile = 289360691352306692L;
	static final long DFile = 578721382704613384L;	
	static final long EFile = 1157442765409226768L;
	static final long FFile = 2314885530818453536L;
	static final long GFile = 4629771061636907072L;
	static final long HFile = -9187201950435737472L;


	//*==============================================================
	//
	//
	//                   Heuristic                   
	//
	//
	//*==============================================================
	private static final int allHeuristic(boolean white) {
		int score = 0;
		if(white) {
			score += wPlayerPiecesOnBoard();
			score += wSafeSquares();
			score += wPossibleMovements();
		} else {
			score += bPlayerPiecesOnBoard();
			score += bSafeSquares();
			score += bPossibleMovements();			
		}
		//	System.out.println(score);
		return score;
	}
	private static final int wPlayerPiecesOnBoard() {
		int score = 0;
		score += (Long.bitCount(WPR) * 20 + Long.bitCount(WPE) * 10);
		score -= (Long.bitCount(BPR) * 20 + Long.bitCount(BPE) * 10);		
		return score;
	}
	private static final int bPlayerPiecesOnBoard() {
		int score = 0;
		score -= (Long.bitCount(WPR) * 20 + Long.bitCount(WPE) * 10);
		score += (Long.bitCount(BPR) * 20 + Long.bitCount(BPE) * 10);		
		return score;
	}
	private static final int wSafeSquares() {
		int score = 0;
		score -= 2 * Long.bitCount((~(wSafeSquare(ALL_WHITE, ALL_BLACK)) & ALL_WHITE));
		return score;
	}
	private static final int bSafeSquares() {
		int score = 0;
		score -= 2 * Long.bitCount((~(bSafeSquare(ALL_BLACK, ALL_WHITE)) & ALL_BLACK));
		return score;	
	}
	private static final int wPossibleMovements() {
		int score = 0;
		score += 3 * Long.bitCount((wPusheeForwardMovement(ALL_WHITE) | wPusheeAnyAttack(WPE) | wPusherAnyAttack(WPR)));
		return score;
	}
	private static final int bPossibleMovements() {
		int score = 0;
		score += 3 * Long.bitCount((bPusheeForwardMovement(ALL_BLACK) | bPusheeAnyAttack(BPE) | bPusherAnyAttack(BPR)));
		return score;
	}
	private static final int Heuristic3() {
		int score = 0;

		return score;
	}
	//*==============================================================
	//
	//
	//                   GENERAL PURPOSE FUNCTIONS                     
	//
	//
	//*==============================================================
	public static final String[] getArrayValidMoves(long playerPawns) {
		int count = countAllValidMoves((playerPawns == ALL_WHITE)? true: false);
		int arrayCount = 0;
		//System.out.println(count);
		String moves[] = new String[count];
		byte[] board = longToByteArray(playerPawns);
		long[] pieces = ((playerPawns == ALL_WHITE)? ALL_WHITE_LIST: ALL_BLACK_LIST);
		for(int i = 0; i < pieces.length; i++) {
			long possibleMoves = pieces[i];
			if(playerPawns == ALL_WHITE) {
				if(wPusheeForwardMovement(possibleMoves) != 0) {
					moves[arrayCount] = INDEX_TO_POS.get(bitScanForward(possibleMoves)) + "-" + INDEX_TO_POS.get(bitScanForward(wPusheeForwardMovement(possibleMoves)));
					//System.out.println(moves[arrayCount]);
					arrayCount++;
				} if(wPusheeEastAttack(possibleMoves) != 0) {
					moves[arrayCount] = INDEX_TO_POS.get(bitScanForward(possibleMoves)) + "-" + INDEX_TO_POS.get(bitScanForward(wPusheeEastAttack(possibleMoves)));
					//System.out.println(moves[arrayCount]);
					arrayCount++;
				} if(wPusheeWestAttack(possibleMoves) != 0) {
					moves[arrayCount] = INDEX_TO_POS.get(bitScanForward(possibleMoves)) + "-" + INDEX_TO_POS.get(bitScanForward(wPusheeWestAttack(possibleMoves)));
					//System.out.println(moves[arrayCount]);
					arrayCount++;
				} if(wPusherEastAttack(possibleMoves) != 0) {
					moves[arrayCount] = INDEX_TO_POS.get(bitScanForward(possibleMoves)) + "-" + INDEX_TO_POS.get(bitScanForward(wPusherEastAttack(possibleMoves)));
					//System.out.println(moves[arrayCount]);
					arrayCount++;
				} if(wPusherWestAttack(possibleMoves) != 0) {
					moves[arrayCount] = INDEX_TO_POS.get(bitScanForward(possibleMoves)) + "-" + INDEX_TO_POS.get(bitScanForward(wPusherWestAttack(possibleMoves)));
					//System.out.println(moves[arrayCount]);
					arrayCount++;
				}
			} if(playerPawns == ALL_BLACK) {
				if(bPusheeForwardMovement(possibleMoves) != 0) {
					moves[arrayCount] = INDEX_TO_POS.get(bitScanForward(possibleMoves)) + "-" + INDEX_TO_POS.get(bitScanForward(bPusheeForwardMovement(possibleMoves)));
					//System.out.println(moves[arrayCount]);
					arrayCount++;
				} if(bPusheeEastAttack(possibleMoves) != 0) {
					moves[arrayCount] = INDEX_TO_POS.get(bitScanForward(possibleMoves)) + "-" + INDEX_TO_POS.get(bitScanForward(bPusheeEastAttack(possibleMoves)));
					//System.out.println(moves[arrayCount]);
					arrayCount++;
				} if(bPusheeWestAttack(possibleMoves) != 0) {
					moves[arrayCount] = INDEX_TO_POS.get(bitScanForward(possibleMoves)) + "-" + INDEX_TO_POS.get(bitScanForward(bPusheeWestAttack(possibleMoves)));
					//System.out.println(moves[arrayCount]);
					arrayCount++;
				} if(bPusherEastAttack(possibleMoves) != 0) {
					moves[arrayCount] = INDEX_TO_POS.get(bitScanForward(possibleMoves)) + "-" + INDEX_TO_POS.get(bitScanForward(bPusherEastAttack(possibleMoves)));
					//System.out.println(moves[arrayCount]);
					arrayCount++;
				} if(bPusherWestAttack(possibleMoves) != 0) {
					moves[arrayCount] = INDEX_TO_POS.get(bitScanForward(possibleMoves)) + "-" + INDEX_TO_POS.get(bitScanForward(bPusherWestAttack(possibleMoves)));
					//System.out.println(moves[arrayCount]);
					arrayCount++;
				}	
			}
		}
		return moves;
	}
	public static final int countAllValidMoves(boolean white) {
		int count = 0;
		if(white) {
			for(int i = 0; i < ALL_WHITE_LIST.length; i++) {
				if(ALL_WHITE_LIST[i] != 0) {
					count += Long.bitCount(wValidMoves(ALL_WHITE_LIST[i]));
				}
			}
		} else {
			for(int i = 0; i < ALL_BLACK_LIST.length; i++) {
				if(ALL_BLACK_LIST[i] != 0) {
					count += Long.bitCount(bValidMoves(ALL_BLACK_LIST[i]));
				}
			}
		}
		return count;
	}
	public static final long getAllValidMoves(long mPiece) {
		return ((wPusheeForwardMovement(mPiece) | wPusheeAnyAttack(mPiece) | wPusherAnyAttack(mPiece)) | ((bPusheeForwardMovement(mPiece) | bPusheeAnyAttack(mPiece) | bPusherAnyAttack(mPiece))));
	}
	public static final long getAllValidMovesForPiece(boolean white, long mPiece) {
		if(white) 
			return wPusheeForwardMovement(mPiece) | wPusheeAnyAttack(mPiece);
		else
			return bPusheeForwardMovement(mPiece) | bPusheeAnyAttack(mPiece);
	}
	public static final boolean validMove(long moveFrom, long moveTo) {
		return (((getAllValidMoves(moveFrom) & moveTo) != 0))? true : false;
	}
	public static final void doMove(String move) {
		move = move.trim();
		String[] tmp = move.trim().split("-");

		long moveFrom = (long)Math.pow(2, POS_TO_INDEX.get(tmp[0]));
		long moveTo = (long)Math.pow(2, POS_TO_INDEX.get(tmp[1]));
		if(POS_TO_INDEX.get(tmp[1]) == 63)
			moveTo = -9223372036854775807L;

		if(validMove(moveFrom, moveTo)) {
			if((moveFrom & ALL_WHITE) != 0 && wValidMoves(moveFrom) != 0) {
				if(wPieceAnyAttack(moveFrom) != 0) {
					if(wPiecesAbleToCaptureAny(moveFrom, moveTo) != 0) {
						CAPTURED_PIECES_INDEX.put(moveNumber, wCapturePieceIndex(moveTo));
						CAPTURED_PIECES.put(moveNumber, wCapturePiece(moveTo));
					}
				}
				updateWhitePieces(moveFrom, moveTo);
			} else if((moveFrom & ALL_BLACK) != 0 && bValidMoves(moveFrom) != 0) {	
				if(bPieceAnyAttack(moveFrom) != 0) {
					if(bPiecesAbleToCaptureAny(moveTo, moveFrom) != 0){
						CAPTURED_PIECES_INDEX.put(moveNumber, bCapturePieceIndex(moveTo));
						CAPTURED_PIECES.put(moveNumber, bCapturePiece(moveTo));
					}
				}
				updateBlackPieces(moveFrom, moveTo);
			}
			moveNumber++;
			ALL_PIECES = ALL_BLACK | ALL_WHITE;
		} else {
			System.out.println("DoMove: " + tmp[0] + "->" + tmp[1] + " TWITCHY TAIL DANGER : INVALID MOVE " +POS_TO_INDEX.get(tmp[0]) + "->" +POS_TO_INDEX.get(tmp[1]));
		}
	}
	public static final void undoMove(String move) {
		moveNumber--;
		move = move.trim();
		String[] tmp = move.trim().split("-");

		long moveFrom = (long)Math.pow(2, POS_TO_INDEX.get(tmp[1]));
		long moveTo = (long)Math.pow(2, POS_TO_INDEX.get(tmp[0]));
		if(POS_TO_INDEX.get(tmp[1]) == 63)
			moveFrom = -9223372036854775807L;

		if(((POS_TO_INDEX.get(tmp[1]) - POS_TO_INDEX.get(tmp[0])) > 0)) {
			updateWhitePieces(moveFrom, moveTo);
			if(CAPTURED_PIECES.containsKey(moveNumber)) {
				resetBlackPiece(CAPTURED_PIECES.get(moveNumber),CAPTURED_PIECES_INDEX.get(moveNumber));
				CAPTURED_PIECES.remove(moveNumber);
				CAPTURED_PIECES_INDEX.remove(moveNumber);
			}
		} else if(((POS_TO_INDEX.get(tmp[1]) - POS_TO_INDEX.get(tmp[0])) < 0)) {
			updateBlackPieces(moveFrom, moveTo);
			if(CAPTURED_PIECES.containsKey(moveNumber)) {
				resetWhitePiece(CAPTURED_PIECES.get(moveNumber),CAPTURED_PIECES_INDEX.get(moveNumber));
				CAPTURED_PIECES.remove(moveNumber);
				CAPTURED_PIECES_INDEX.remove(moveNumber);
			}
		}
		ALL_PIECES = ALL_BLACK | ALL_WHITE;	
	}
	//*==============================================================
	//
	//
	//                   WHITE PLAYER MOVES
	//                        
	//
	//
	//*=============================================================
	public final static void resetWhitePiece(long wPiece, int i) {
		ALL_WHITE_LIST[i] = wPiece;
		if(i == 0) 
			WHITE_PUSHEE_1 = wPiece;
		if(i == 1) 
			WHITE_PUSHEE_2 = wPiece;
		if(i == 2) 
			WHITE_PUSHEE_3 = wPiece;
		if(i == 3) 
			WHITE_PUSHEE_4 = wPiece;
		if(i == 4) 
			WHITE_PUSHEE_5 = wPiece;
		if(i == 5) 
			WHITE_PUSHEE_6 = wPiece;
		if(i == 6) 
			WHITE_PUSHEE_7 = wPiece;
		if(i == 7) 
			WHITE_PUSHEE_8 = wPiece;
		if(i == 8) 
			WHITE_PUSHER_1 = wPiece;
		if(i == 9) 
			WHITE_PUSHER_2 = wPiece;
		if(i == 10) 
			WHITE_PUSHER_3 = wPiece;
		if(i == 11) 
			WHITE_PUSHER_4 = wPiece;
		if(i == 12) 
			WHITE_PUSHER_5 = wPiece;
		if(i == 13) 
			WHITE_PUSHER_6 = wPiece;
		if(i == 14) 
			WHITE_PUSHER_7 = wPiece;
		if(i == 15) 
			WHITE_PUSHER_8 = wPiece;
		updateWhiteValues();
	}
	public final static void eliminateWhitePiece(long wPiece) {
		for(int i = 0; i < ALL_WHITE_LIST.length; i++) {
			if((ALL_WHITE_LIST[i] & wPiece) != 0) {
				ALL_WHITE_LIST[i] = 0;
				if(i == 0) 
					WHITE_PUSHEE_1 = 0;
				if(i == 1) 
					WHITE_PUSHEE_2 = 0;
				if(i == 2) 
					WHITE_PUSHEE_3 = 0;
				if(i == 3) 
					WHITE_PUSHEE_4 = 0;
				if(i == 4) 
					WHITE_PUSHEE_5 = 0;
				if(i == 5) 
					WHITE_PUSHEE_6 = 0;
				if(i == 6) 
					WHITE_PUSHEE_7 = 0;
				if(i == 7) 
					WHITE_PUSHEE_8 = 0;
				if(i == 8) 
					WHITE_PUSHER_1 = 0;
				if(i == 9) 
					WHITE_PUSHER_2 = 0;
				if(i == 10) 
					WHITE_PUSHER_3 = 0;
				if(i == 11) 
					WHITE_PUSHER_4 = 0;
				if(i == 12) 
					WHITE_PUSHER_5 = 0;
				if(i == 13) 
					WHITE_PUSHER_6 = 0;
				if(i == 14) 
					WHITE_PUSHER_7 = 0;
				if(i == 15) 
					WHITE_PUSHER_8 = 0;
			}
		}
		updateWhiteValues();
	}
	public final static void updateWhiteValues() {
		WPE = WHITE_PUSHEE_1 | WHITE_PUSHEE_2 | WHITE_PUSHEE_3 | WHITE_PUSHEE_4 | WHITE_PUSHEE_5 | WHITE_PUSHEE_6 | WHITE_PUSHEE_7 | WHITE_PUSHEE_8;
		WPR = WHITE_PUSHER_1 | WHITE_PUSHER_2 | WHITE_PUSHER_3 | WHITE_PUSHER_4 | WHITE_PUSHER_5 | WHITE_PUSHER_6 | WHITE_PUSHER_7 | WHITE_PUSHER_8;
		ALL_WHITE = WPE | WPR;
	}
	public final static void updateWhitePieces(long moveFrom, long moveTo) {
		if((moveFrom & WPE) != 0) {
			updateWhitePushee(moveFrom, moveTo);
		} 
		if((moveFrom & WPR) != 0) {
			updateWhitePusher(moveFrom, moveTo);
		}
		ALL_WHITE = WPE | WPR;
	}
	public final static void updateWhitePusher(long moveFrom, long moveTo) {
		if(moveFrom == WHITE_PUSHER_1) {
			WHITE_PUSHER_1 = moveTo;
			ALL_WHITE_LIST[8] = WHITE_PUSHER_1;
		} else if(moveFrom == WHITE_PUSHER_2) {
			WHITE_PUSHER_2 = moveTo;
			ALL_WHITE_LIST[9] = WHITE_PUSHER_2;
		} else if(moveFrom == WHITE_PUSHER_3) {
			WHITE_PUSHER_3 = moveTo;
			ALL_WHITE_LIST[10] = WHITE_PUSHER_3;
		} else if(moveFrom == WHITE_PUSHER_4) {
			WHITE_PUSHER_4 = moveTo;
			ALL_WHITE_LIST[11] = WHITE_PUSHER_4;
		} else if(moveFrom == WHITE_PUSHER_5) {
			WHITE_PUSHER_5 = moveTo;
			ALL_WHITE_LIST[12] = WHITE_PUSHER_5;
		} else if(moveFrom == WHITE_PUSHER_6) {
			WHITE_PUSHER_6 = moveTo;
			ALL_WHITE_LIST[13] = WHITE_PUSHER_6;
		} else if(moveFrom == WHITE_PUSHER_7) {
			WHITE_PUSHER_7 = moveTo;
			ALL_WHITE_LIST[14] = WHITE_PUSHER_7;
		} else if(moveFrom == WHITE_PUSHER_8) {
			WHITE_PUSHER_8 = moveTo;
			ALL_WHITE_LIST[15] = WHITE_PUSHER_8;
		}
		WPR = WHITE_PUSHER_1 | WHITE_PUSHER_2 | WHITE_PUSHER_3 | WHITE_PUSHER_4 | WHITE_PUSHER_5 | WHITE_PUSHER_6 | WHITE_PUSHER_7 | WHITE_PUSHER_8;
	}
	public final static void updateWhitePushee(long moveFrom, long moveTo) {
		if(moveFrom == WHITE_PUSHEE_1) {
			WHITE_PUSHEE_1 = moveTo;
			ALL_WHITE_LIST[0] = WHITE_PUSHEE_1;
		} else if(moveFrom == WHITE_PUSHEE_2){ 
			WHITE_PUSHEE_2 = moveTo;
			ALL_WHITE_LIST[1] = WHITE_PUSHEE_2;
		} else if(moveFrom == WHITE_PUSHEE_3) {
			WHITE_PUSHEE_3 = moveTo;
			ALL_WHITE_LIST[2] = WHITE_PUSHEE_3;
		} else if(moveFrom == WHITE_PUSHEE_4) { 
			WHITE_PUSHEE_4 = moveTo;
			ALL_WHITE_LIST[3] = WHITE_PUSHEE_4;
		} else if(moveFrom == WHITE_PUSHEE_5) {
			WHITE_PUSHEE_5 = moveTo;
			ALL_WHITE_LIST[4] = WHITE_PUSHEE_5;
		} else if(moveFrom == WHITE_PUSHEE_6) {
			WHITE_PUSHEE_6 = moveTo;
			ALL_WHITE_LIST[5] = WHITE_PUSHEE_6;
		} else if(moveFrom == WHITE_PUSHEE_7) {
			WHITE_PUSHEE_7 = moveTo;
			ALL_WHITE_LIST[6] = WHITE_PUSHEE_7;
		} else if(moveFrom == WHITE_PUSHEE_8) { 
			WHITE_PUSHEE_8 = moveTo;
			ALL_WHITE_LIST[7] = WHITE_PUSHEE_8;
		}
		//.out.println("UPDATE" + " " + moveFrom  + " TO " + moveTo);
		WPE = WHITE_PUSHEE_1 | WHITE_PUSHEE_2 | WHITE_PUSHEE_3 | WHITE_PUSHEE_4 | WHITE_PUSHEE_5 | WHITE_PUSHEE_6 | WHITE_PUSHEE_7 | WHITE_PUSHEE_8;
	}
	public final static int getTotalWhiteMoves() {
		int totalMoves = 0;
		long bitNumber = 0;
		byte[] whitePieces = longToByteArray(ALL_WHITE);
		for(int i = 0; i < whitePieces.length; i++) {
			for(int k = 0; k < 8; k++) {
				if(getBit(whitePieces, k+(8*i)) != 0) {
					bitNumber = (long)Math.pow(2, k+(8*i));
					if(wPusheeEastAttack(bitNumber) != 0)
						totalMoves++;
					if(wPusheeWestAttack(bitNumber) != 0)
						totalMoves++;
					if(wPusheeForwardMovement(bitNumber) != 0)
						totalMoves++;
				}
			}
		}
		return totalMoves;
	}
	public final static long wValidMoves(long mPiece) {
		return (wPusheeForwardMovement(mPiece) | wPusheeAnyAttack(mPiece) | wPusherAnyAttack(mPiece));
	}
	public final static long wPusheeValidEastAttack(long wPiece) {
		return (WPR & (wPiece >>> 9) & ~(HFile));
	}
	public final static long wPusheeValidWestAttack(long wPiece) {
		return (WPR & (wPiece >>> 7) & ~(AFile));
	}
	public final static long wPusheeValidForwardMove(long wPiece) {
		return (WPR & (wPiece >>> 8));
	}
	public final static long wPusheeEastAttack(long wPieces) {
		if((wPieces & WPE) != 0)
			return (wPusheeValidEastAttack(wPieces) != 0) ? ((wPieces & ~(HFile|AFile)) << 9) & ~(ALL_WHITE) : 0; 
			return 0;
	}
	public final static long wPusheeWestAttack(long wPieces) {
		if((wPieces & WPE) != 0)
			return (wPusheeValidWestAttack(wPieces) != 0) ?  ((wPieces & ~(AFile|HFile)) << 7) & ~(ALL_WHITE) : 0;
			return 0;
	}
	public final static long wPusherEastAttack(long wPieces) {
		if((wPieces & WPR) != 0)
			return ((wPieces & ~(HFile)) << 9) & ~(ALL_WHITE);
		return 0;
	}
	public final static long wPusherWestAttack(long wPieces) {
		if((wPieces & WPR) != 0)
			return ((wPieces & ~(AFile)) << 7) & ~(ALL_WHITE);
		return 0;
	}
	//move to ---- move From
	public final static long wPiecesAbleToCaptureAny(long wPieces, long bPieces) {
		return wPieceAnyAttack(wPieces) & (bPieces & ALL_BLACK);
	}
	public final static long wPieceAnyAttack(long wPieces) {
		return wPusherAnyAttack(wPieces) | wPusheeAnyAttack(wPieces);
	}
	public final static long wPusheeAnyAttack(long wPieces) {
		return wPusheeEastAttack(wPieces) | wPusheeWestAttack(wPieces);
	}
	public final static long wPusherAnyAttack(long wPieces) {
		return wPusherEastAttack(wPieces) | wPusherWestAttack(wPieces);
	}
	public final static long wPusheeDblAttack(long wPieces) {
		return wPusheeEastAttack(wPieces) & wPusheeWestAttack(wPieces);
	}
	public final static long wPusheeSingleAttack(long wPieces) {
		return wPusheeEastAttack(wPieces) ^ wPusheeWestAttack(wPieces);
	}
	public final static long wPusheeForwardMovement(long wPieces) {
		if((wPieces & WPE) != 0)
			return (wPusheeValidForwardMove(wPieces) != 0) ? wPieces << 8 & ~(ALL_PIECES) : 0;
			else if((wPieces & WPR) != 0)
				return wPieces << 8 & ~(ALL_PIECES);
		return 0;
	}
	public final static long wPiecesAbleToCaptureEast(long wPieces, long bPieces) {
		return wPieces & bPusheeWestAttack(bPieces);
	}
	public final static long wPiecesAbleToCaptureWest(long wPieces, long bPieces) {
		return wPieces & bPusheeEastAttack(bPieces);
	}
	public final static long wCapturePiece(long wPiece) {
		long bCaptured = 0;
		for(int i = 0; i < ALL_BLACK_LIST.length; i++) {
			if((wPiece & ALL_BLACK_LIST[i]) != 0) {
				bCaptured = ALL_BLACK_LIST[i];
				eliminateBlackPiece(ALL_BLACK_LIST[i]);
				ALL_BLACK_LIST[i] = 0;
			}
		}
		return bCaptured;
	}
	public final static int wCapturePieceIndex(long wPiece) {
		for(int i = 0; i < ALL_BLACK_LIST.length; i++) {
			if((wPiece & ALL_BLACK_LIST[i]) != 0) {
				return i;
			}
		}
		return 0;
	}
	//Calculate Safe Squares
	public final static long wSafeSquare(long wPieces, long bPieces) {
		long whiteEastAttacks = wPusheeEastAttack(wPieces) | wPusherEastAttack(wPieces);
		long whiteWestAttacks = wPusheeWestAttack(wPieces) | wPusherWestAttack(wPieces);
		long blackEastAttacks = bPusheeEastAttack(bPieces) | bPusherEastAttack(wPieces);
		long blackWestAttacks = bPusheeWestAttack(bPieces) | bPusherWestAttack(wPieces);
		long wPieceDblAttack = whiteEastAttacks & whiteWestAttacks;
		long wPieceOddAttack = whiteEastAttacks ^ whiteWestAttacks;
		long bPieceDblAttack = blackEastAttacks & blackWestAttacks;
		long bPieceAnyAttack = blackEastAttacks | blackWestAttacks;
		return wPieceDblAttack | ~bPieceAnyAttack | (wPieceOddAttack & ~bPieceDblAttack);
	}
	//*==============================================================
	//
	//
	//                   BLACK PLAYER MOVES
	//                   
	//
	//
	//*==============================================================
	public final static void resetBlackPiece(long bPiece, int i) {
		ALL_BLACK_LIST[i] = bPiece;
		if(i == 0) 
			BLACK_PUSHEE_1 = bPiece;
		if(i == 1) 
			BLACK_PUSHEE_2 = bPiece;
		if(i == 2) 
			BLACK_PUSHEE_3 = bPiece;
		if(i == 3) 
			BLACK_PUSHEE_4 = bPiece;
		if(i == 4) 
			BLACK_PUSHEE_5 = bPiece;
		if(i == 5) 
			BLACK_PUSHEE_6 = bPiece;
		if(i == 6) 
			BLACK_PUSHEE_7 = bPiece;
		if(i == 7) 
			BLACK_PUSHEE_8 = bPiece;
		if(i == 8) 
			BLACK_PUSHER_1 = bPiece;
		if(i == 9) 
			BLACK_PUSHER_2 = bPiece;
		if(i == 10) 
			BLACK_PUSHER_3 = bPiece;
		if(i == 11) 
			BLACK_PUSHER_4 = bPiece;
		if(i == 12) 
			BLACK_PUSHER_5 = bPiece;
		if(i == 13) 
			BLACK_PUSHER_6 = bPiece;
		if(i == 14) 
			BLACK_PUSHER_7 = bPiece;
		if(i == 15) 
			BLACK_PUSHER_8 = bPiece;
		updateBlackValues();
	}
	public final static void eliminateBlackPiece(long bPiece) {
		for(int i = 0; i < ALL_BLACK_LIST.length; i++) {
			if((ALL_BLACK_LIST[i] & bPiece) != 0) {
				ALL_BLACK_LIST[i] = 0;
				if(i == 0) 
					BLACK_PUSHEE_1 = 0;
				if(i == 1) 
					BLACK_PUSHEE_2 = 0;
				if(i == 2) 
					BLACK_PUSHEE_3 = 0;
				if(i == 3) 
					BLACK_PUSHEE_4 = 0;
				if(i == 4) 
					BLACK_PUSHEE_5 = 0;
				if(i == 5) 
					BLACK_PUSHEE_6 = 0;
				if(i == 6) 
					BLACK_PUSHEE_7 = 0;
				if(i == 7) 
					BLACK_PUSHEE_8 = 0;
				if(i == 8) 
					BLACK_PUSHER_1 = 0;
				if(i == 9) 
					BLACK_PUSHER_2 = 0;
				if(i == 10) 
					BLACK_PUSHER_3 = 0;
				if(i == 11) 
					BLACK_PUSHER_4 = 0;
				if(i == 12) 
					BLACK_PUSHER_5 = 0;
				if(i == 13) 
					BLACK_PUSHER_6 = 0;
				if(i == 14) 
					BLACK_PUSHER_7 = 0;
				if(i == 15) 
					BLACK_PUSHER_8 = 0;
			}
		}
		updateBlackValues();
	}
	public final static void updateBlackValues() {
		BPR = BLACK_PUSHER_1 | BLACK_PUSHER_2 | BLACK_PUSHER_3 | BLACK_PUSHER_4 | BLACK_PUSHER_5 | BLACK_PUSHER_6 | BLACK_PUSHER_7 | BLACK_PUSHER_8;
		BPE = BLACK_PUSHEE_1 | BLACK_PUSHEE_2 | BLACK_PUSHEE_3 | BLACK_PUSHEE_4 | BLACK_PUSHEE_5 | BLACK_PUSHEE_6 | BLACK_PUSHEE_7 | BLACK_PUSHEE_8;
		ALL_BLACK = BPE | BPR;
	}
	public final static void updateBlackPieces(long moveFrom, long moveTo) {
		if((moveFrom & BPE) != 0)  {
			updateBlackPushee(moveFrom, moveTo);
		} 
		if((moveFrom & BPR) != 0) {
			updateBlackPusher(moveFrom, moveTo);
		}
		ALL_BLACK = BPE | BPR;
	}
	public final static void updateBlackPusher(long moveFrom, long moveTo) {
		if(moveFrom == BLACK_PUSHER_1) {
			BLACK_PUSHER_1 = moveTo;
			ALL_BLACK_LIST[8] = BLACK_PUSHER_1;
		} else if(moveFrom == BLACK_PUSHER_2) {
			BLACK_PUSHER_2 = moveTo;
			ALL_BLACK_LIST[9] = BLACK_PUSHER_2;
		} else if(moveFrom == BLACK_PUSHER_3) {
			BLACK_PUSHER_3 = moveTo;
			ALL_BLACK_LIST[10] = BLACK_PUSHER_3;
		} else if(moveFrom == BLACK_PUSHER_4) {
			BLACK_PUSHER_4 = moveTo;
			ALL_BLACK_LIST[11] = BLACK_PUSHER_4;
		} else if(moveFrom == BLACK_PUSHER_5) {
			BLACK_PUSHER_5 = moveTo;
			ALL_BLACK_LIST[12] = BLACK_PUSHER_5;
		} else if(moveFrom == BLACK_PUSHER_6) {
			BLACK_PUSHER_6 = moveTo;
			ALL_BLACK_LIST[13] = BLACK_PUSHER_6;
		} else if(moveFrom == BLACK_PUSHER_7) {
			BLACK_PUSHER_7 = moveTo;
			ALL_BLACK_LIST[14] = BLACK_PUSHER_7;
		} else if(moveFrom == BLACK_PUSHER_8) {
			BLACK_PUSHER_8 = moveTo;
			ALL_BLACK_LIST[15] = BLACK_PUSHER_8;
		}
		BPR = BLACK_PUSHER_1 | BLACK_PUSHER_2 | BLACK_PUSHER_3 | BLACK_PUSHER_4 | BLACK_PUSHER_5 | BLACK_PUSHER_6 | BLACK_PUSHER_7 | BLACK_PUSHER_8;
	}
	public final static void updateBlackPushee(long moveFrom, long moveTo) {
		if(moveFrom == BLACK_PUSHEE_1) {
			BLACK_PUSHEE_1 = moveTo;
			ALL_BLACK_LIST[0] = BLACK_PUSHEE_1;
		} else if(moveFrom == BLACK_PUSHEE_2) {
			BLACK_PUSHEE_2 = moveTo;
			ALL_BLACK_LIST[1] = BLACK_PUSHEE_2;
		} else if(moveFrom == BLACK_PUSHEE_3) {
			BLACK_PUSHEE_3 = moveTo;
			ALL_BLACK_LIST[2] = BLACK_PUSHEE_3;
		} else if(moveFrom == BLACK_PUSHEE_4) {
			BLACK_PUSHEE_4 = moveTo;
			ALL_BLACK_LIST[3] = BLACK_PUSHEE_4;
		} else if(moveFrom == BLACK_PUSHEE_5) {
			BLACK_PUSHEE_5 = moveTo;
			ALL_BLACK_LIST[4] = BLACK_PUSHEE_5;
		} else if(moveFrom == BLACK_PUSHEE_6) {
			BLACK_PUSHEE_6 = moveTo;
			ALL_BLACK_LIST[5] = BLACK_PUSHEE_6;
		} else if(moveFrom == BLACK_PUSHEE_7) {
			BLACK_PUSHEE_7 = moveTo;
			ALL_BLACK_LIST[6] = BLACK_PUSHEE_7;
		} else if(moveFrom == BLACK_PUSHEE_8) {
			BLACK_PUSHEE_8 = moveTo;
			ALL_BLACK_LIST[7] = BLACK_PUSHEE_8;
		}
		BPE = BLACK_PUSHEE_1 | BLACK_PUSHEE_2 | BLACK_PUSHEE_3 | BLACK_PUSHEE_4 | BLACK_PUSHEE_5 | BLACK_PUSHEE_6 | BLACK_PUSHEE_7 | BLACK_PUSHEE_8;
	}
	public final static int getTotalBlackMoves() {
		int totalMoves = 0;
		long bitNumber = 0;
		byte[] blackPieces = longToByteArray(ALL_BLACK);
		for(int i = 0; i < blackPieces.length; i++) {
			for(int k = 0; k < 8; k++) {
				if(getBit(blackPieces, k+(8*i)) != 0) {
					bitNumber = (long)Math.pow(2, k+(8*i));
					if(bPusheeEastAttack(bitNumber) != 0)
						totalMoves++;
					if(bPusheeWestAttack(bitNumber) != 0)
						totalMoves++;
					if(bPusheeForwardMovement(bitNumber) != 0)
						totalMoves++;
					System.out.println(INDEX_TO_POS.get(k+(8*i)) + " " + Long.toBinaryString(bValidMoves(bitNumber)));
				}
			}
		}
		return totalMoves;
	}
	public final static long bSafeSquare(long wPieces, long bPieces) {
		long whiteEastAttacks = wPusheeEastAttack(wPieces);
		long whiteWestAttacks = wPusheeWestAttack(wPieces);
		long blackEastAttacks = bPusheeEastAttack(bPieces);
		long blackWestAttacks = bPusheeWestAttack(bPieces);
		long bPieceDblAttack = blackEastAttacks & blackWestAttacks;
		long bPieceOddAttack = blackEastAttacks ^ blackWestAttacks;
		long wPieceDblAttack = whiteEastAttacks & whiteWestAttacks;
		long wPieceAnyAttack = whiteEastAttacks | whiteWestAttacks;
		return bPieceDblAttack | ~wPieceAnyAttack | (bPieceOddAttack & ~wPieceDblAttack);		
	}
	public final static long bValidMoves(long mPiece) {
		return bPusheeForwardMovement(mPiece) | bPusheeAnyAttack(mPiece) | bPusherAnyAttack(mPiece);
	}
	public final static long bPusheeAnyAttack(long bPieces) {
		return bPusheeEastAttack(bPieces) | bPusheeWestAttack(bPieces);
	}
	public final static long bPusheeDblAttack(long bPieces) {
		return bPusheeEastAttack(bPieces) & bPusheeWestAttack(bPieces);
	}
	public final static long bPusheeSingleAttack(long bPieces) {
		return bPusheeEastAttack(bPieces) ^ bPusheeWestAttack(bPieces);
	}
	public final static long bPusheeValidEastAttack(long bPieces) {
		return (BPR & (bPieces << 9) & ~(AFile));
	}
	public final static long bPusheeValidWestAttack(long bPieces) {
		return (BPR & (bPieces << 7) & ~(HFile));
	}
	public final static long bPusheeValidForwardMove(long bPiece) {
		return (BPR & (bPiece << 8));
	}
	public final static long bPusheeEastAttack(long bPieces) {
		if((bPieces & BPE) != 0)
			return (bPusheeValidEastAttack(bPieces) != 0)? ((bPieces & ~(AFile|HFile))  >>> 7 ) & ~(ALL_BLACK) : 0;
			return 0;
	}
	public final static long bPusheeWestAttack(long bPieces) {
		if((bPieces & BPE) != 0)
			return (bPusheeValidWestAttack(bPieces) != 0)? ((bPieces & ~(AFile|HFile))  >>> 9 ) & ~(ALL_BLACK) : 0;
			return 0;
	}
	public final static long bPieceAnyAttack(long bPieces) {
		return bPusherAnyAttack(bPieces) | bPusheeAnyAttack(bPieces);
	}
	public final static long bPusherAnyAttack(long bPieces) {
		return bPusherEastAttack(bPieces) | bPusherWestAttack(bPieces);
	}
	public final static long bPusherEastAttack(long bPieces) {
		if((bPieces & BPR) != 0)
			return ((bPieces & ~(HFile)) >>> 7) & ~(ALL_BLACK);
		return 0;
	}
	public final static long bPusherWestAttack(long bPieces) {
		if((bPieces & BPR) != 0)
			return ((bPieces & ~(AFile)) >>> 9) & ~(ALL_BLACK);
		return 0;
	}
	public final static long bPusheeForwardMovement(long bPieces) {
		if((bPieces & BPE) != 0)
			return (bPusheeValidForwardMove(bPieces) != 0) ? bPieces >>> 8 & ~(ALL_PIECES) : 0;
			else if ((bPieces & BPR) != 0)
				return bPieces >>> 8 & ~(ALL_PIECES);
			return 0;
	}
	public final static long bPiecesAbleToCaptureEast(long wPieces, long bPieces) {
		return bPieces & wPusheeWestAttack(wPieces);
	}
	public final static long bPiecesAbleToCaptureWest(long wPieces, long bPieces) {
		return bPieces & wPusheeEastAttack(wPieces);
	}
	//MoveTo ---- MoveFrom
	public final static long bPiecesAbleToCaptureAny(long wPieces, long bPieces) {
		return bPieceAnyAttack(bPieces) & (wPieces & ALL_WHITE);
	}
	public final static long bCapturePiece(long bPiece) {
		long wCaptured = 0;
		for(int i = 0; i < ALL_WHITE_LIST.length; i++) {
			if((bPiece & ALL_WHITE_LIST[i]) != 0) {
				wCaptured = ALL_WHITE_LIST[i];
				eliminateWhitePiece(ALL_WHITE_LIST[i]);
				ALL_WHITE_LIST[i] = 0;
			}
		}
		return wCaptured;
	}
	public final static int bCapturePieceIndex(long bPiece) {
		for(int i = 0; i < ALL_WHITE_LIST.length; i++) {
			if((bPiece & ALL_WHITE_LIST[i]) != 0) {
				return i;
			}
		}
		return 0;
	}	
	//*==============================================================
	//
	//                   POSITION FUNCTIONS
	//
	//
	//*==============================================================	
	private final static int[] getPieceIndex(int squareIndex) {
		int[] indeces = new int[2];
		indeces[0] =  squareIndex & 7;
		indeces[1] =  squareIndex >> 3;
		return indeces;
	}
	private static final byte[] longToByteArray(long l) {
		byte[] result = new byte[8];

		result[7] = (byte) ((l >>> 56));
		result[6] = (byte) ((l >>> 48));
		result[5] = (byte) ((l >>> 40));
		result[4] = (byte) ((l >>> 32));
		result[3] = (byte) ((l >>> 24));
		result[2] = (byte) ((l >>> 16));
		result[1] = (byte) ((l >>> 8));
		result[0] = (byte) ((l >>> 0));
		return result;
	}
	private static final int getBit(byte[] data, int pos) {
		int posByte = pos/8;
		int posBit = pos%8;
		byte valByte = data[posByte];
		int valInt = valByte>>(8-(posBit+1)) & 0x0001;
		return valInt;
	}
	private static final int bitScanForward(long bb) { 
		return Long.bitCount(( (bb & -bb) - 1 ));
	}
	private static final int bitScanReverse(long bb) {
		int result = 0;
		if (bb > 0xFFFFFFFF) {
			bb >>= 32;
			result = 32;
		}
		if (bb > 0xFFFF) {
			bb >>= 16;
			result += 16;
		}
		if (bb > 0xFF) {
			bb >>= 8;
			result += 8;
		}
		return result;
	}
	//*==============================================================
	//
	//                   BITBOARD FUNCTIONS
	//
	//
	//*==============================================================
	public static final void updateAllValues() {
		ALL_PIECES = ALL_WHITE | ALL_BLACK;
	}
	public static final void printNiceCurrentBoard() {
		String wPushees = Long.toBinaryString(WPE);
		wPushees = String.format("%64s", wPushees).replace(' ', '0').replace('1', 'o');
		String wPushers = Long.toBinaryString(WPR);
		wPushers = String.format("%64s", wPushers).replace(' ', '0').replace('1', 'O');
		String bPushees = Long.toBinaryString(BPE);
		bPushees = String.format("%64s", bPushees).replace(' ', '0').replace('1', 'x');
		String bPushers = Long.toBinaryString(BPR);
		bPushers = String.format("%64s", bPushers).replace(' ', '0').replace('1', 'X');

		char[] wPEchar = wPushees.toCharArray();
		char[] wPRchar = wPushers.toCharArray();
		char[] bPEchar = bPushees.toCharArray();
		char[] bPRchar = bPushers.toCharArray();	
		String[] strArray = new String[64];

		for(int i = 0; i <= 63; i++) {
			if(wPEchar[i] != '0') {
				strArray[i] = wPEchar[i]+"";
			} else if(wPRchar[i] != '0') {
				strArray[i] = wPRchar[i]+"";
			} else if(bPEchar[i] != '0') {
				strArray[i] = bPEchar[i]+"";
			} else if(bPRchar[i] != '0') {
				strArray[i] = bPRchar[i]+"";
			} else {
				strArray[i] = "-";
			}
		}

		System.out.println(); //Make sure nothing gets in the way of the board

		for(int j = 0; j < wPushees.length()/8; j++) {
			System.out.print(8-j+"| ");
			for(int k = 7; k >= 0; k--) {
				System.out.print(strArray[(j * 8) + k] + " ");
			}
			System.out.println("");
			if(j==7) {
				System.out.println("  ================");
				System.out.println("   A B C D E F G H ");
			}
		}	

	}
	/*
		//pos++;
		if(depth == 0)
		{
		 //GameUtils.printBoard(game.getBoard());
		 masterCpt++;
			return 50;
		}
		else
		{
			int score = -100;
			int max = -100;
			ArrayList<int[][]> moves = game.getAllValidMoves(white);
			for (int i = 0; i < moves.size(); i++)
			{
				game.doMove(moves.get(i));
				score = 0;

			//	LogPush.getInstance().storeFilePusherLine(game.getBoard(), moves.get(i));


				int val = -negamax(depth-1, !white, 0, 0, 1);
				game.undoMove(moves.get(i));
			}
			return pos;
	 */
	public static String bestMove = "";
	public static int bestScore = 0;
	public static boolean currentPlayer = false;
	public static final int NegaMax(int depth, boolean white, String currentMove) {
		String[] moves = null;
		if(depth == 0) {
			int score = allHeuristic(currentPlayer);
			if(bestScore < score) {
				bestScore = score;
			}
			return score;
		}
		if(white) {
			moves = getArrayValidMoves(ALL_WHITE);
		} else {
			moves = getArrayValidMoves(ALL_BLACK);
		}
		for (int i = 0; i < moves.length; i++) {
			doMove(moves[i]);
			//System.out.println("Depth: " + depth  + " Moves: " + moves[i]);
			int score = -NegaMax(depth-1, !white, moves[i]);
			if(bestScore == score) {
				bestScore = score;
				bestMove = currentMove;
			}
			undoMove(moves[i]);
		}
		return -1;
	}
	public static final void printCurrentBitBoard() {
		printCurrentBitBoardWithValue(ALL_PIECES);
	}
	public static final String bit64String(long binaryStr) {
		return String.format("%64s", Long.toBinaryString(binaryStr)).replace(' ', '0');
	}
	public static final void printCurrentBitBoardWithValue(long mPieces) {
		String str = Long.toBinaryString(mPieces);
		//String str = Long.toBinaryString(wPusheeEastAttack(WPE) | BPR);
		str = String.format("%64s", str).replace(' ', '0');
		for(int i = 0; i < str.length(); i++) {
			if((i) % 8 == 0)
				System.out.print(" | ");
			System.out.print(str.charAt(i));
		}
		System.out.println(" | ");

		System.out.println("-----------------------------------------------------------------");
		for(int j = 0; j < str.length()/8; j++) {
			System.out.print("| ");
			for(int k = 7; k >= 0; k--) {
				System.out.print(String.format("%02d",((((str.length()-1)/8)-j) * 8  + (7-k))) + ": " + str.charAt((j * 8) + k) + " | ");
			}
			System.out.println();
			System.out.println("-----------------------------------------------------------------");
		}

	}
	public static void main(String[] args) {
		doThis();
		//allHeuristic(true);
		//NegaMax(4,true, null);
		//System.out.println(bestMove + " : " + bestScore);
		System.exit(0);
		String[] moves = null;
		boolean white = true;
		ArrayList<String> ListMoves = new ArrayList<String>();
		for(int k = 0; k <= 0;k++) {
			if(ListMoves.size() > 0) {
				//System.out.println("RESET BOARD");
				for(int j = ListMoves.size()-1; j >= 0; j--) {
					undoMove(ListMoves.get(j));
					//System.out.println("undoMove(\"" + ListMoves.get(j) + "\");");
				}
				//printNiceCurrentBoard();
				for(int j = 0; j <= ListMoves.size()-1; j++) {
					//System.out.println("doMove(\"" + ListMoves.get(j) + "\");");
				}
				for(int j = ListMoves.size()-1; j >= 0; j--) {
					//System.out.println("undoMove(\"" + ListMoves.get(j) + "\");");
				}		
				//System.out.println("printNiceCurrentBoard();");
			}
			ListMoves = new ArrayList<String>();
			try {
				do {
					currentPlayer = !currentPlayer;
					NegaMax(4,white, null);
					white = !white;
					System.out.println(bestMove + " : " + bestScore);
					String moveToPlay = bestMove;
					bestMove = null; bestScore = 0;
					/*
					if(white) {
						moves = getArrayValidMoves(ALL_WHITE);
					} else {
						moves = getArrayValidMoves(ALL_BLACK);
					}
					white = !white;
					String moveToPlay = moves[(new Random()).nextInt(moves.length-1)];
					 */
					//System.out.println("ARRLENGTH " + moves.length + " RANDOM: " + rand  + " PLAYING MOVE " + moveToPlay);
					//ListMoves.add("doMove(\"" + moveToPlay + "\");");
					ListMoves.add(moveToPlay);
					//System.out.println("doMove(\"" + moveToPlay + "\");");
					doMove(moveToPlay);
					printNiceCurrentBoard();
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						System.out.println(e.getMessage());
						break;
					}
				} while((ALL_WHITE & RANK8) == 0 && (ALL_BLACK & RANK1) == 0);
				//System.out.println("Number: " + k + " ~!WINNER DETECTED!~" + ListMoves.size());
			} catch (Exception e) {
				for(int i = 0; i < ListMoves.size(); i++) {
					System.out.println(ListMoves.get(i));
				}
			}
			//printCurrentBitBoard();
		}
		//printCurrentBitBoardWithValue((BPR));
	}
	private static final void doThis() {
		 miniMaxAB(ALL_PIECES, true, 0, 4, true, -10000, 10000);
		//doMove("B7-B6");
		//doMove("C7-C6");
		//doMove("D7-D6");
		//doMove("E7-E6");
		//doMove("F7-F6");
		//doMove("G7-G6");
		//doMove("H7-H6");

		//doMove("B2-B3");
		//doMove("C2-C3");
		//doMove("D2-D3");
		//doMove("E2-E3");
		//doMove("F2-F3");
		//doMove("G2-G3");
		//doMove("H2-H3");
		//printNiceCurrentBoard();
	}


	public static int miniMaxAB(long currentBoard, boolean player, int depth, int maxDepth, boolean whoToMax, int alpha, int beta)
	{
		String[] moves = null;
		if (depth == maxDepth)
		{
			tmpInt[0] = allHeuristic(player);
			//System.out.println("For this board: ");

			// GameUtils.printBoard(currentBoard);

			//tmpInt[1] = currentNode.getUniqueID();
			//masterCpt++;
			return tmpInt[0];
		}

		if (whoToMax == player) // Will execute if it's the MAX player turn to play
		{
			int[] alphaLocal = new int[2];
			alphaLocal[0] = -10000;

			//ArrayList<int[][]> moves = GameUtils.getAllValidMoves(currentBoard, player);
			//ArrayList<int[][]> boards = GameUtils.convertMovesToArray(currentBoard, moves);
			if(player) {
				moves = getArrayValidMoves(ALL_WHITE);
			} else {
				moves = getArrayValidMoves(ALL_BLACK);
			}
			for (int i = 0; i < moves.length; i++)
			{
				doMove(moves[i]);
				//GameUtils.printBoard(newBoard);

				score = miniMaxAB(ALL_PIECES, !player, depth+1, maxDepth, whoToMax, Math.max(alpha, alphaLocal[0]), beta);
				doMove(moves[i]);
				alphaLocal[0] = Math.max(alphaLocal[0], score);

				if (alphaLocal[0] > beta)
				{
					//alphaLocal[1] = currentNode.getUniqueID();
					return alphaLocal[0];
				}
				if (alphaLocal[0] == score)
				{
					//alphaLocal[1] = newNode.getUniqueID();
				}

				//System.out.println("In MAX for node with uniqueID: " + newNode.getUniqueID()+ " score is: " + score[0] + " alphaLocal is: " + alphaLocal[0] + " alpha is: " + alpha + " beta is: " + beta);
				System.out.println("In MAX for node score is: " + score + " alphaLocal is: " + alphaLocal[0] + " alpha is: " + alpha + " beta is: " + beta);
				System.out.println("*** MaxScore is now at: " + alphaLocal[0]);
			}
			return alphaLocal[0];
		}
		else // Will execute if it's the MIN player turn to play
		{
			int[] betaLocal = new int[2];
			betaLocal[0] = 10000;

			if(player) {
				moves = getArrayValidMoves(ALL_WHITE);
			} else {
				moves = getArrayValidMoves(ALL_BLACK);
			}
			for (int i = 0; i < moves.length; i++)
			{
				doMove(moves[i]);
				long newBoard = ALL_PIECES;
				//GameUtils.printBoard(newBoard);

				score = miniMaxAB(ALL_PIECES, !player, depth+1, maxDepth, whoToMax, alpha, Math.min(betaLocal[0], beta));
				undoMove(moves[i]);
				betaLocal[0] = Math.min(betaLocal[0], score);
				if (betaLocal[0] < alpha)
				{
					// betaLocal[1] = currentNode.getUniqueID();
					return betaLocal[0];
				}
				if (betaLocal[0] == score)
				{
					// betaLocal[1] = newNode.getUniqueID();
				}
				// System.out.println("In MIN for node with uniqueID: " + newNode.getUniqueID()+ " score is: " + score[0] + " betaLocal is: " + betaLocal[0] + " beta is: " + beta + " alpha is: " + alpha);
				System.out.println("In MIN for node score is: " + score + " betaLocal is: " + betaLocal[0] + " beta is: " + beta + " alpha is: " + alpha);
				System.out.println("*** MinScore is now at: " + betaLocal[0]);
			}
			return betaLocal[0];
		}
	}
}